`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/04/25 11:37:55
// Design Name: 
// Module Name: fifo_manager
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

//`define fifo_read_used    1
//`define sim 1

module fifo_manager#(
        parameter   axi_data_width          =   512         ,//Support 32,64,128,256,512 
        parameter   fifo_memory_type        =   "block"     ,
        parameter   fifo_memory_deep        =   512         ,       
        parameter   d_cnt_width             =   9        //fifo_data_count_width:2^d_cnt_width = fifo_memory_deep
)(
    input   wire                            sys_clk     ,
    input   wire                            sys_rst     ,
//---------------------write  interfacec-------------------
//  write fifo data input
    input   wire    [axi_data_width-1:0]    wr_fifo_in          ,//
    input   wire                            wr_fifo_en          ,//
            
    output  wire                            wr_fifo_full            ,
    output  wire    [d_cnt_width-1:0]       wr_fifo_data_count  ,
    output  wire                            wr_fifo_empty       ,
//  data_out fifo
    output  wire    [axi_data_width-1:0]    wr_out              ,//
    output  wire                            wr_out_valid            ,//
    input   wire                            wr_out_ready            ,//
//---------------------read  interfacec-------------------
//  data_in fifo    
    input   wire    [axi_data_width-1:0]    rd_fifo_in          ,//
    input   wire                            rd_fifo_en          ,//
    output  wire                            rd_fifo_ready       ,
    
    output  wire                            rd_fifo_full        ,
    output  wire    [d_cnt_width-1:0]       rd_fifo_data_count  ,
    output  wire                            rd_fifo_empty       ,   
//  data_out fifo
    output  wire    [axi_data_width-1:0]    rd_out              ,//
    output  reg                             rd_out_valid        //      
    );
    
//  
    reg         rd_en_0 ;           
    wire        valid   ;					 						 
/*    xpm_fifo_sync #(
      .DOUT_RESET_VALUE("0"),    // String
      .ECC_MODE("no_ecc"),       // String
      .FIFO_MEMORY_TYPE(fifo_memory_type), // String
      .FIFO_READ_LATENCY(1),     // DECIMAL
      .FIFO_WRITE_DEPTH(fifo_memory_deep),   // DECIMAL
      .FULL_RESET_VALUE(0),      // DECIMAL
      .PROG_EMPTY_THRESH(10),    // DECIMAL
      .PROG_FULL_THRESH(10),     // DECIMAL
      .RD_DATA_COUNT_WIDTH(d_cnt_width),   // DECIMAL
      .READ_DATA_WIDTH(axi_data_width),      // DECIMAL
      .READ_MODE("fwft"),         // String
      .USE_ADV_FEATURES("1707"), // String
      .WAKEUP_TIME(0),           // DECIMAL
      .WRITE_DATA_WIDTH(axi_data_width),     // DECIMAL
      .WR_DATA_COUNT_WIDTH(d_cnt_width)    // DECIMAL
   )
   xpm_fifo_sync_inst_u0 (
	  .data_valid			(valid					),						 
      .dout                 (wr_out                 ),                  
      .empty                (wr_fifo_empty          ),                
      .full                 (wr_fifo_full           ),                  
      .wr_data_count        (wr_fifo_data_count     ), 
      .din                  (wr_fifo_in             ),                   
      .rd_en                (rd_en_0                ),                
      .rst                  (sys_rst                ),                                
      .wr_clk               (sys_clk                ),               
      .wr_en                (wr_fifo_en             )                  
   );  */  
      fifo_generator_0 your_instance_name (
        .clk            (sys_clk        ),                    // input wire clk
        .srst           (sys_rst        ),                  // input wire srst
        .din            (wr_fifo_in     ),                    // input wire [511 : 0] din
        .wr_en          (wr_fifo_en     ),                // input wire wr_en
        .rd_en          (rd_en_0        ),                // input wire rd_en
        .dout           (wr_out         ),                  // output wire [511 : 0] dout
        .full           (wr_fifo_full   ),                  // output wire full
        .empty          (wr_fifo_empty  ),                // output wire empty
		.data_count		(wr_fifo_data_count),  // output wire [9 : 0] data_count
        .valid          (valid          )                // output wire valid
    );
//`ifdef sim  
/*     reg         wr_out_ready_sim;
    reg [7:0]   cnt;
    reg         wr_out_valid_0;
    always @(posedge sys_clk)
        if(sys_rst)
            cnt <= 'd0;
        else 
            cnt <= cnt + 1'd1;
    always @(*)
        case(cnt)
            8'd99   : wr_out_ready_sim = 'd0;
            8'd100  : wr_out_ready_sim = 'd0;
            
            default : wr_out_ready_sim = wr_out_ready;
        endcase
        
    always @(*) rd_en_0 = wr_out_ready_sim & !wr_fifo_empty;
    
    always @(posedge sys_clk)   
        if((wr_out_ready_sim & wr_fifo_empty  ) | sys_rst)
            wr_out_valid_0 <= 1'd0;
        else if(rd_en_0)
            wr_out_valid_0 <= 1'd1;
        else 
            wr_out_valid_0 <= wr_out_valid_0;   
        
    assign wr_out_valid = wr_out_valid_0 & wr_out_ready_sim;   */
//`else   
    always @(*) rd_en_0 = wr_out_ready & !wr_fifo_empty;
    
/*     always @(posedge sys_clk)   
        if((wr_out_ready & wr_fifo_empty) | sys_rst)
            wr_out_valid <= 1'd0;
        else if(rd_en_0)
            wr_out_valid <= 1'd1;
        else 
            wr_out_valid <= wr_out_valid; */
 assign wr_out_valid = valid;

//`endif  
    
    

`ifdef fifo_read_used   
//
    reg     rd_en_1;
   xpm_fifo_sync #(
      .DOUT_RESET_VALUE("0"),    // String
      .ECC_MODE("no_ecc"),       // String
      .FIFO_MEMORY_TYPE(fifo_memory_type), // String
      .FIFO_READ_LATENCY(1),     // DECIMAL
      .FIFO_WRITE_DEPTH(fifo_memory_deep),   // DECIMAL
      .FULL_RESET_VALUE(0),      // DECIMAL
      .PROG_EMPTY_THRESH(10),    // DECIMAL
      .PROG_FULL_THRESH(10),     // DECIMAL
      .RD_DATA_COUNT_WIDTH(d_cnt_width),   // DECIMAL
      .READ_DATA_WIDTH(axi_data_width),      // DECIMAL
      .READ_MODE("std"),         // String
      .USE_ADV_FEATURES("0707"), // String
      .WAKEUP_TIME(0),           // DECIMAL
      .WRITE_DATA_WIDTH(axi_data_width),     // DECIMAL
      .WR_DATA_COUNT_WIDTH(d_cnt_width)    // DECIMAL
   )
   xpm_fifo_sync_inst_u1 (
      .dout                 (rd_out             ),                  
      .empty                (rd_fifo_empty      ),                
      .full                 (rd_fifo_full       ),                  
      .rd_data_count        (rd_fifo_data_count ), 
      .din                  (rd_fifo_in         ),                   
      .rd_en                (rd_en_1            ),                
      .rst                  (sys_rst            ),                              
      .wr_clk               (sys_clk            ),               
      .wr_en                (rd_fifo_en         )                  
   );
    
    always @(*) rd_en_1 = !rd_fifo_empty;
    
    always @(posedge sys_clk) rd_out_valid <= rd_en_1;
    assign  rd_fifo_ready = !rd_fifo_full;
`else
    
    assign  rd_fifo_full  = 1'd0;
    assign  rd_fifo_empty = 1'd0;
    assign  rd_fifo_data_count  =   {(d_cnt_width){1'd0}};
    assign  rd_out = rd_fifo_in;
    assign  rd_fifo_ready = 1'd1;
    always @(*)rd_out_valid = rd_fifo_en;
    
    
`endif
endmodule
